package simulaco.dao;

import gminet.infra.dao.DataAccessObject;
import gminet.infra.db.TransactionException;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import simulaco.dto.Usuario;
import simulaco.dto.UsuarioSituacao;
import simulaco.dto.UsuarioPerfil;


public class UsuarioDAO extends DataAccessObject {

    public static Usuario findByPK(int usuarioCodigo, Connection conn) throws TransactionException {

        StringBuffer sbSql = new StringBuffer();
        sbSql.append("SELECT A.CD_USUARIO      CD_USUARIO  ");
        sbSql.append("     , A.TX_NOME         TX_NOME     ");
        sbSql.append("     , A.TX_EMAIL        TX_EMAIL    ");
        sbSql.append("     , A.ID_SITUACAO     ID_SITUACAO ");
        sbSql.append("     , A.ID_PERFIL       ID_PERFIL   ");
        sbSql.append("     , A.TS_CADASTRO     TS_CADASTRO ");
        sbSql.append("  FROM USUARIO        A ");
        sbSql.append(" WHERE A.CD_USUARIO = ? ");

        Usuario usuario = null;
        try {
            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            setInt(ps, 1, usuarioCodigo);
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                usuario = fromResultSet(rs);
            }
            close(ps);
        } catch (SQLException sqle) {
            throw new TransactionException("UsuarioDAO.findByPK (" + sqle.getMessage() + ")");
        }
        return usuario;
    }

    public static Usuario findByEmail(String email, Connection conn) throws TransactionException {

        StringBuffer sbSql = new StringBuffer();
        sbSql.append("SELECT A.CD_USUARIO      CD_USUARIO  ");
        sbSql.append("     , A.TX_NOME         TX_NOME     ");
        sbSql.append("     , A.TX_EMAIL        TX_EMAIL    ");
        sbSql.append("     , A.ID_SITUACAO     ID_SITUACAO ");
        sbSql.append("     , A.ID_PERFIL       ID_PERFIL   ");
        sbSql.append("     , A.TS_CADASTRO     TS_CADASTRO ");
        sbSql.append("  FROM USUARIO        A ");
        sbSql.append(" WHERE A.TX_EMAIL = ? ");

        Usuario usuario = null;
        try {
            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            setString(ps, 1, email);
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                usuario = fromResultSet(rs);
            }
            close(ps);
        } catch (SQLException sqle) {
            throw new TransactionException("UsuarioDAO.findByEmail (" + sqle.getMessage() + ")");
        }
        return usuario;
    }

    public static boolean existEmail(String email, Connection conn) throws TransactionException {

        return existEmail(email, 0, conn);
    }

    public static boolean existEmail(String email, int codigo, Connection conn) throws TransactionException {

        boolean found = false;
        StringBuffer sbSql = new StringBuffer();
        sbSql.append("SELECT CD_USUARIO   ");
        sbSql.append("  FROM USUARIO      ");
        sbSql.append(" WHERE TX_EMAIL = ? ");
        try {
            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            setString(ps, 1, email);
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                int cdUsuario = getInt(rs, "CD_USUARIO");
                found = codigo == 0 || cdUsuario != codigo;
            }
            close(ps);
        } catch (SQLException sqle) {
            throw new TransactionException("UsuarioDAO.existEmail (" + sqle.getMessage() + ")");
        }
        return found;
    }

    public static List<Usuario> findAll(Connection conn) throws TransactionException {

        StringBuffer sbSql = new StringBuffer();
        sbSql.append("SELECT A.CD_USUARIO      CD_USUARIO  ");
        sbSql.append("     , A.TX_NOME         TX_NOME     ");
        sbSql.append("     , A.TX_EMAIL        TX_EMAIL    ");
        sbSql.append("     , A.ID_SITUACAO     ID_SITUACAO ");
        sbSql.append("     , A.ID_PERFIL       ID_PERFIL   ");
        sbSql.append("     , A.TS_CADASTRO     TS_CADASTRO ");
        sbSql.append("  FROM USUARIO    A ");
        sbSql.append(" ORDER BY A.TX_NOME ");
        List<Usuario> usuariosList = new ArrayList<Usuario>(100);
        try {
            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                Usuario usuario = fromResultSet(rs);
                usuariosList.add(usuario);
            }
            close(rs);
        } catch (SQLException sqle) {
            throw new TransactionException("UsuarioDAO.findAll (" + sqle.getMessage() + ")");
        }
        return usuariosList;
    }

    public static List<Usuario> findByFilter(UsuarioFilter filter, Connection conn) throws TransactionException {

        StringBuffer sbSql = new StringBuffer();
        sbSql.append("SELECT A.CD_USUARIO      CD_USUARIO  ");
        sbSql.append("     , A.TX_NOME         TX_NOME     ");
        sbSql.append("     , A.TX_EMAIL        TX_EMAIL    ");
        sbSql.append("     , A.ID_SITUACAO     ID_SITUACAO ");
        sbSql.append("     , A.ID_PERFIL       ID_PERFIL   ");
        sbSql.append("     , A.TS_CADASTRO     TS_CADASTRO ");
        sbSql.append("  FROM USUARIO A ");
        sbSql.append(" WHERE 1 = 1 ");
        if (filter.hasPrimeiroDigito()) {
            String strLetra = filter.getPrimeiroDigito().toLowerCase();
            if (strLetra.equalsIgnoreCase("0")) {
                sbSql.append(" AND LEFT(A.TX_NOME, 1) < 'A'");
            } else {
                sbSql.append(" AND LOWER(A.TX_NOME) like '" + strLetra + "%' ");
            }
        }
        if (filter.hasNome()) {
            String strName = filter.getNome().toLowerCase();
            sbSql.append(" AND LOWER(A.TX_NOME) like '%" + strName + "%' ");
        }
        if (filter.hasEmail()) {
            String strEmail = filter.getEmail().toLowerCase();
            sbSql.append(" AND LOWER(A.TX_EMAIL) like '%" + strEmail + "%' ");
        }
        if (filter.hasCodigoSituacao()) {
            sbSql.append(" AND A.ID_SITUACAO = ? ");
        }
        if (filter.hasCodigoPerfil()) {
            sbSql.append(" AND A.ID_PERFIL = ? ");
        }
        sbSql.append(" ORDER BY A.TX_NOME ");
        List<Usuario> usuariosList = new ArrayList<Usuario>(100);
        try {
            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            int pos = 1;
            if (filter.hasCodigoSituacao()) {
                setInt(ps, pos++, filter.getCodigoSituacao());
            }
            if (filter.hasCodigoPerfil()) {
                setInt(ps, pos++, filter.getCodigoPerfil());
            }
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                Usuario usuario = fromResultSet(rs);
                usuariosList.add(usuario);
            }
            close(rs);
        } catch (SQLException sqle) {
            throw new TransactionException("UsuarioDAO.findByFilter (" + sqle.getMessage() + ")");
        }
        return usuariosList;
    }

    public static String findSenhaAcesso(int usuarioCodigo, Connection conn) throws TransactionException {

        StringBuffer sbSql = new StringBuffer();
        sbSql.append("SELECT A.CD_USUARIO      CD_USUARIO  ");
        sbSql.append("     , A.TX_ACESSO       TX_ACESSO   ");
        sbSql.append("  FROM USUARIO        A ");
        sbSql.append(" WHERE A.CD_USUARIO = ? ");

        String senhaAcesso = null;
        try {
            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            setInt(ps, 1, usuarioCodigo);
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                senhaAcesso = getString(rs, "TX_ACESSO");
            }
            close(ps);
        } catch (SQLException sqle) {
            throw new TransactionException("UsuarioDAO.findSenhaAcesso (" + sqle.getMessage() + ")");
        }
        return senhaAcesso;
    }

    public static void insert(Usuario usuario, Connection conn) throws TransactionException {

        StringBuffer sbSql = new StringBuffer();
        sbSql.append("INSERT INTO USUARIO    ");
        sbSql.append("     ( CD_USUARIO      ");
        sbSql.append("     , TX_NOME         ");
        sbSql.append("     , TX_EMAIL        ");
        sbSql.append("     , ID_SITUACAO     ");
        sbSql.append("     , ID_PERFIL       ");
        sbSql.append("     , TX_ACESSO       ");
        sbSql.append("     , TS_CADASTRO     ");
        sbSql.append(") VALUES (?,?,?,?,?,?,?)");
        try {
            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            int pos = 1;
            setInt(ps, pos++, usuario.getCodigo());
            setString(ps, pos++, usuario.getNome());
            setString(ps, pos++, usuario.getEmail());
            setInt(ps, pos++, usuario.getSituacao().getCodigo());
            setInt(ps, pos++, usuario.getPerfil().getCodigo());
            setString(ps, pos++, usuario.getSenhaAcesso());
            setTimestamp(ps, pos++, usuario.getDataCadastro());
            ps.executeUpdate();
            close(ps);
        } catch (SQLException sqle) {
            throw new TransactionException("UsuarioDAO.insert (" + sqle.getMessage() + ")");
        }
    }

    public static void update(Usuario usuario, Connection conn) throws TransactionException {

        StringBuffer sbSql = new StringBuffer();
        sbSql.append("UPDATE USUARIO           ");
        sbSql.append("   SET TX_NOME       = ? ");
        sbSql.append("     , TX_EMAIL      = ? ");
        sbSql.append("     , ID_SITUACAO   = ? ");
        sbSql.append("     , ID_PERFIL     = ? ");
        sbSql.append(" WHERE CD_USUARIO    = ? ");
        try {
            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            int pos = 1;
            setString(ps, pos++, usuario.getNome());
            setString(ps, pos++, usuario.getEmail());
            setInt(ps, pos++, usuario.getSituacao().getCodigo());
            setInt(ps, pos++, usuario.getPerfil().getCodigo());
            setInt(ps, pos++, usuario.getCodigo());
            ps.executeUpdate();
            close(ps);
        } catch (SQLException sqle) {
            throw new TransactionException("UsuarioDAO.update (" + sqle.getMessage() + ")");
        }
    }

    public static void updatePassword(Usuario usuario, Connection conn) throws TransactionException {

        StringBuffer sbSql = new StringBuffer();
        sbSql.append("UPDATE USUARIO         ");
        sbSql.append("   SET TX_ACESSO = ? ");
        sbSql.append(" WHERE CD_USUARIO  = ? ");
        try {
            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            int pos = 1;
            setString(ps, pos++, usuario.getSenhaAcesso());
            setInt(ps, pos++, usuario.getCodigo());
            ps.executeUpdate();
            close(ps);
        } catch (SQLException sqle) {
            throw new TransactionException("UsuarioDAO.updatePassword (" + sqle.getMessage() + ")");
        }
    }

    public static void delete(Usuario usuario, Connection conn) throws TransactionException {

        StringBuffer sbSql = new StringBuffer();
        sbSql.append("DELETE FROM USUARIO  ");
        sbSql.append(" WHERE CD_USUARIO = ?");
        try {
            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            setInt(ps, 1, usuario.getCodigo());
            ps.executeUpdate();
            close(ps);
        } catch (SQLException sqle) {
            throw new TransactionException("UsuarioDAO.delete (" + sqle.getMessage() + ")");
        }
    }

    public static int getNextCodigo(Connection conn, int iRange, int eRange) throws TransactionException {

        try {
            StringBuffer sbSql = new StringBuffer();
            sbSql.append("SELECT MAX(CD_USUARIO) AS CD_MAX ");
            sbSql.append("  FROM USUARIO        ");
            sbSql.append(" WHERE CD_USUARIO > ? ");
            sbSql.append("   AND CD_USUARIO < ? ");

            PreparedStatement ps = conn.prepareStatement(sbSql.toString());
            setInt(ps, 1, iRange);
            setInt(ps, 2, eRange);
            ResultSet rs = ps.executeQuery();
            int max = 0;
            if (rs.next()) {
                max = rs.getInt("CD_MAX");
            }
            close(rs);
            return (max != 0 ? max : iRange) + 1;
        } catch (SQLException sqlEx) {
            throw new TransactionException(sqlEx);
        }
    }

    private static Usuario fromResultSet(ResultSet rs) throws SQLException {

        // USUARIO
        Usuario usuario = new Usuario();
        usuario.setCodigo(getInt(rs, "CD_USUARIO"));
        usuario.setNome(getString(rs, "TX_NOME"));
        usuario.setEmail(getString(rs, "TX_EMAIL"));
        usuario.setSituacao(UsuarioSituacao.getSituacaoById(getByte(rs, "ID_SITUACAO")));
        usuario.setPerfil(UsuarioPerfil.getPerfilById(getByte(rs, "ID_PERFIL")));
        usuario.setDataCadastro(getDateFromTimestamp(rs, "TS_CADASTRO"));
        //
        return usuario;
    }

}
